import json
import logging
from typing import Dict, List, Any, Tuple, Set
from concurrent.futures import ThreadPoolExecutor, as_completed
from collections import defaultdict
import threading

from elasticsearch import Elasticsearch
from config.settings import ES_HOST, INDEX_NAME

logger = logging.getLogger(__name__)

class PatentAnalysisService:
    def __init__(self):
        self.es = Elasticsearch(
            ES_HOST, 
            request_timeout=120
        )
        self.inventor_cache = {}
        self.cache_lock = threading.Lock()
    
    def _parse_inventor_names(self, inventor_field: Any) -> List[str]:
        """解析发明人姓名字段"""
        if not inventor_field:
            return []
        
        try:
            if isinstance(inventor_field, str):
                if inventor_field.startswith('[') and inventor_field.endswith(']'):
                    inventor_field = json.loads(inventor_field)
                else:
                    return [name.strip() for name in inventor_field.replace(';', ',').split(',') if name.strip()]
            
            if isinstance(inventor_field, list):
                names = []
                for item in inventor_field:
                    names.append(str(item).strip())
                return [name for name in names if name]
            
            return [str(inventor_field).strip()]
            
        except Exception as e:
            logger.warning(f"解析发明人姓名错误: {e}")
            return []
    
    def _get_inventor_all_patents(self, inventor_name: str, applicant_name: str) -> List[Dict[str, Any]]:
        """获取发明人的所有专利"""
        cache_key = f"{inventor_name}|{applicant_name}"
        
        with self.cache_lock:
            if cache_key in self.inventor_cache:
                return self.inventor_cache[cache_key]
        
        try:
            query = {
                "query": {
                    "bool": {
                        "must": [
                            {"match": {"inventor_name": {"query": inventor_name, "operator": "and"}}},
                            {"term": {"applicant_name.keyword": applicant_name}}
                        ]
                    }
                },
                "_source": ["_id", "invention_title", "abstract", "inventor_name", 
                           "applicant_name", "applicant_address", "publication_date"],
                "size": 10000
            }
            
            response = self.es.search(index=INDEX_NAME, body=query)
            hits = response.get('hits', {}).get('hits', [])
            
            patents = []
            for hit in hits:
                patent = hit['_source'].copy()
                patent['_id'] = hit['_id']
                patents.append(patent)
            
            with self.cache_lock:
                self.inventor_cache[cache_key] = patents
            
            return patents
            
        except Exception as e:
            logger.error(f"查询发明人专利错误: {e}")
            return []

    def _get_inventors_all_patents_bulk(self, inventor_pairs: List[Tuple[str, str]]) -> Dict[str, List[Dict[str, Any]]]:
        """批量获取多个(发明人, 申请人)对的所有专利，合并缓存，减少ES请求次数"""
        result: Dict[str, List[Dict[str, Any]]] = {}
        to_query: List[Tuple[str, str]] = []
        
        # 先读取缓存
        with self.cache_lock:
            for inventor_name, applicant_name in inventor_pairs:
                cache_key = f"{inventor_name}|{applicant_name}"
                if cache_key in self.inventor_cache:
                    result[cache_key] = self.inventor_cache[cache_key]
                else:
                    to_query.append((inventor_name, applicant_name))
        
        if not to_query:
            return result
        
        try:
            # 构建should查询，一次性返回所有命中这些(发明人,申请人)组合的专利
            to_query_set: Set[Tuple[str, str]] = set(to_query)
            should_clauses = []
            for inventor_name, applicant_name in to_query:
                should_clauses.append({
                    "bool": {
                        "must": [
                            {"match": {"inventor_name": {"query": inventor_name, "operator": "and"}}},
                            {"term": {"applicant_name.keyword": applicant_name}}
                        ]
                    }
                })
            
            query = {
                "query": {
                    "bool": {
                        "should": should_clauses,
                        "minimum_should_match": 1
                    }
                },
                "_source": ["_id", "invention_title", "abstract", "inventor_name", 
                           "applicant_name", "applicant_address", "publication_date"],
                "size": 10000
            }
            
            response = self.es.search(index=INDEX_NAME, body=query)
            hits = response.get('hits', {}).get('hits', [])
            
            grouped: Dict[str, List[Dict[str, Any]]] = {}
            for hit in hits:
                src = hit.get('_source', {})
                app = src.get('applicant_name', '')
                inv_list = self._parse_inventor_names(src.get('inventor_name', []))
                # 一个专利可能对应多个发明人，将其分配到命中的(发明人,申请人)组合
                for inv in inv_list:
                    if (inv, app) in to_query_set:
                        key = f"{inv}|{app}"
                        patent = src.copy()
                        patent['_id'] = hit['_id']
                        grouped.setdefault(key, []).append(patent)
            
            # 写回缓存并补全结果
            with self.cache_lock:
                for inventor_name, applicant_name in to_query:
                    key = f"{inventor_name}|{applicant_name}"
                    patents = grouped.get(key, [])
                    self.inventor_cache[key] = patents
                    result[key] = patents
            
            return result
        except Exception as e:
            logger.error(f"批量查询发明人专利错误: {e}")
            # 查询失败时，确保未命中的键也返回空列表
            for inventor_name, applicant_name in to_query:
                key = f"{inventor_name}|{applicant_name}"
                result.setdefault(key, [])
            return result
    
    def _count_inventor_in_topic_patents(self, inventor_name: str, applicant_name: str, topic_patents: List[Dict]) -> int:
        """统计发明人在主题专利中的出现次数"""
        count = 0
        for patent in topic_patents:
            inventor_names = self._parse_inventor_names(patent.get('inventor_name', []))
            patent_applicant = patent.get('applicant_name', '')
            
            if inventor_name in inventor_names and patent_applicant == applicant_name:
                count += 1
        return count
    
    async def analyze_inventors(self, patents: List[Dict[str, Any]]) -> Dict[str, Any]:
        """分析发明人信息（批量查询ES，避免对每个发明人单独请求）"""
        logger.info(f"开始分析 {len(patents)} 个专利的发明人信息")
        
        # 收集所有唯一的发明人（发明人名+申请人名组合）
        unique_inventors: Set[Tuple[str, str]] = set()
        for patent in patents:
            inventor_names = self._parse_inventor_names(patent.get('inventor_name', []))
            applicant_name = patent.get('applicant_name', '')
            for inventor_name in inventor_names:
                if inventor_name.strip():
                    unique_inventors.add((inventor_name, applicant_name))
        
        # 统计主题内每个(发明人,申请人)出现次数
        topic_count_map: Dict[str, int] = defaultdict(int)
        for patent in patents:
            inv_names = self._parse_inventor_names(patent.get('inventor_name', []))
            app = patent.get('applicant_name', '')
            for inv in inv_names:
                if inv.strip():
                    topic_count_map[f"{inv}|{app}"] += 1
        
        # 批量获取所有人的专利列表（结合缓存，只为未缓存的对发起一次ES查询）
        all_patents_map = self._get_inventors_all_patents_bulk(list(unique_inventors))
        
        # 组装结果
        inventors_analysis: Dict[str, Any] = {}
        for inventor_name, applicant_name in unique_inventors:
            key = f"{inventor_name}|{applicant_name}"
            all_patents = all_patents_map.get(key, [])
            inventors_analysis[key] = {
                'inventor_name': inventor_name,
                'applicant_name': applicant_name,
                'all_patents': all_patents,
                'all_count': len(all_patents),
                'topic_count': topic_count_map.get(key, 0)
            }
        
        logger.info(f"发明人分析完成，共分析 {len(inventors_analysis)} 个发明人")
        return inventors_analysis
    
    def _analyze_single_inventor(self, inventor_name: str, applicant_name: str, topic_patents: List[Dict]) -> Dict[str, Any]:
        """分析单个发明人"""
        # 获取该发明人的所有专利
        all_patents = self._get_inventor_all_patents(inventor_name, applicant_name)
        
        # 统计在主题中的专利数量
        topic_count = self._count_inventor_in_topic_patents(inventor_name, applicant_name, topic_patents)
        
        return {
            'inventor_name': inventor_name,
            'applicant_name': applicant_name,
            'all_patents': all_patents,
            'all_count': len(all_patents),
            'topic_count': topic_count
        }

